package com.jihox.abookpro.view;

import java.util.LinkedList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListAdapter;

import com.jihox.abookpro.ChangeSequenceActivity.ChangeSequenceAdapter;
import com.jihox.abookpro.util.CalDis;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ObjectAnimator;

/**
 *
 */
public class ChangeSequenceGridView extends GridView{
	private long dragResponseMS = 10;

	private boolean isDrag = false;
	private int mDownX;
	private int mDownY;
	private int mUpX;
	private int mUpY;
	private int moveX;
	private int moveY;
	private int mDragPosition;

	private boolean mAnimationEnd = true;

	private View mStartDragItemView = null;

	private ImageView mDragImageView;

	private WindowManager mWindowManager;
	private WindowManager.LayoutParams mWindowLayoutParams;

	private Bitmap mDragBitmap;

	private int mPoint2ItemTop ; 

	private int mPoint2ItemLeft;

	private int mOffset2Top;

	private int mOffset2Left;

	private int mStatusHeight; 

	private int mRightScrollBorder;

	private int mLeftScrollBorder;

	private OnReorderItemsListener onReorderItemsListener;

	private ChangeSequenceAdapter mDragAdapter;

	public ChangeSequenceGridView(Context context) {
		this(context, null);
	}

	public ChangeSequenceGridView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public ChangeSequenceGridView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		mStatusHeight = getStatusHeight(context); 
	}

	private Handler mHandler = new Handler();

	private Runnable mLongClickRunnable = new Runnable() {
		@Override
		public void run() {
			isDrag = true;
			createDragImage(mDragBitmap, mDownX, mDownY);
		}
	};


	@Override
	public void setAdapter(ListAdapter adapter) {
		super.setAdapter(adapter);

		if(adapter instanceof ChangeSequenceAdapter){
			mDragAdapter = (ChangeSequenceAdapter) adapter;
		}else{
			throw new IllegalStateException("the adapter must be implements DragAdapter");
		}
	}

	public void setOnReorderItemsListener(
			OnReorderItemsListener onReorderItemsListener) {
		this.onReorderItemsListener = onReorderItemsListener;
	}

	public void setDragResponseMS(long dragResponseMS) {
		this.dragResponseMS = dragResponseMS;
	}

	private int moveBefore=0,moveAfter=0,moveDis=0;
	private int rawMoveX;
	private boolean oneClickFlag = true;
	private long flingHorizontalViewStartTime = 0;
	private long flingHorizontalViewEndTime = 0;
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
	
		switch(ev.getAction()){
		case MotionEvent.ACTION_DOWN:
			flingHorizontalViewStartTime = System.currentTimeMillis();

			oneClickFlag = true;//点击了
			mHandler.postDelayed(mLongClickRunnable, dragResponseMS);

			moveBefore=mDownX = (int) ev.getX();
			mDownY = (int) ev.getY();

			mDragPosition = pointToPosition(mDownX, mDownY);

			if(mDragPosition == AdapterView.INVALID_POSITION || mDragPosition == 0){
				return super.dispatchTouchEvent(ev);
			}

			mStartDragItemView = getChildAt(mDragPosition - getFirstVisiblePosition());

			mPoint2ItemTop = mDownY - mStartDragItemView.getTop();
			mPoint2ItemLeft = mDownX - mStartDragItemView.getLeft();

			mOffset2Top = (int) (ev.getRawY() - mDownY);
			mOffset2Left = (int) (ev.getRawX() - mDownX);
			mStartDragItemView.setDrawingCacheEnabled(true);
			mDragBitmap = Bitmap.createBitmap(mStartDragItemView.getDrawingCache());
			mStartDragItemView.destroyDrawingCache();

			break;
		case MotionEvent.ACTION_MOVE:

			int moveX = (int)ev.getX();
			int moveY = (int) ev.getY();

			if(!isTouchInItem(mStartDragItemView, moveX, moveY)){
				mHandler.removeCallbacks(mLongClickRunnable);
			}
			break;
		case MotionEvent.ACTION_UP:
			oneClickFlag = true;
			mUpX = (int) ev.getX();
			mUpY = (int) ev.getY();
			mHandler.removeCallbacks(mLongClickRunnable);
			mHandler.removeCallbacks(mScrollRunnable);
			break;
		}
		return super.dispatchTouchEvent(ev);
	}

	private boolean isTouchInItem(View dragView, int x, int y){
		if(dragView == null){
			return false;
		}
		int leftOffset = dragView.getLeft();
		int topOffset = dragView.getTop();
		if(x < leftOffset || x > leftOffset + dragView.getWidth()){
			return false;
		}

		if(y < topOffset || y > topOffset + dragView.getHeight()){
			return false;
		}

		return true;
	}

	private Runnable galleryHorizontalScrollRunnable = new Runnable() {

		@Override
		public void run() {
			oneClickFlag = false;
		}
	};
	private Runnable galleryHorizontalFlingRunnable = new Runnable() {

		@Override
		public void run() {
			mHandler.removeCallbacks(mLongClickRunnable);
			oneClickFlag = false;

			int velocity = (int)(5000*moveDis/(flingHorizontalViewEndTime-flingHorizontalViewStartTime));

			if(velocity>10000){
				velocity=10000;
			}else if(velocity<-10000){
				velocity=-10000;
			}

			moveAfter = 0;
			moveDis = 0;
			moveBefore = 0;
		}
	};	

	@Override
	public boolean onTouchEvent(MotionEvent ev) {

		if(isDrag && mDragImageView != null){
			switch(ev.getAction()){
			case MotionEvent.ACTION_MOVE:
				rawMoveX = (int) ev.getRawX();
				moveX = (int) ev.getX();
				moveY = (int) ev.getY();
				onDragItem(moveX, moveY);
				break;
			case MotionEvent.ACTION_UP:
				onStopDrag();
				isDrag = false;
				break;
			}
			return true;
		}else if(CalDis.calDis(mDownX, mDownY, mUpX, mUpY)<3&&oneClickFlag){
			return true;
		}else{//拖动来
			switch(ev.getAction()){
			case MotionEvent.ACTION_MOVE:
				moveAfter = (int) ev.getX();
				moveDis = moveBefore - moveAfter;
				moveAfter = moveBefore;
				//				moveAfter = galleryHorizontalView.getScrollX();
				mHandler.post(galleryHorizontalScrollRunnable);
				if(CalDis.calDis(mDownX, mDownY, ev.getX(), ev.getY())>7){
					mHandler.removeCallbacks(mLongClickRunnable);
				}
				break;
			case MotionEvent.ACTION_CANCEL:
				moveAfter = 0;
				moveDis = 0;
				moveBefore = 0;
				break;	
			case MotionEvent.ACTION_UP:
				flingHorizontalViewEndTime = System.currentTimeMillis();
				mHandler.post(galleryHorizontalFlingRunnable);
				break;
			}
			return true;
		}
	}

	private void createDragImage(Bitmap bitmap, int downX , int downY){
		mWindowLayoutParams = new WindowManager.LayoutParams();
		mWindowLayoutParams.format = PixelFormat.TRANSLUCENT; 
		mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
		mWindowLayoutParams.x = downX - mPoint2ItemLeft + mOffset2Left;
		mWindowLayoutParams.y = downY - mPoint2ItemTop + mOffset2Top - mStatusHeight;
		mWindowLayoutParams.alpha = 0.55f; 
		mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;  
		mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;  
		mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  
				| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE ;

		mDragImageView = new ImageView(getContext());  
		mDragImageView.setImageBitmap(bitmap);  
		mWindowManager.addView(mDragImageView, mWindowLayoutParams);  
	}

	private void removeDragImage(){
		if(mDragImageView != null){
			mWindowManager.removeView(mDragImageView);
			mDragImageView = null;
		}
	}

	private void onDragItem(int moveX, int moveY){
		mWindowLayoutParams.x = moveX - mPoint2ItemLeft + mOffset2Left;
		mWindowLayoutParams.y = moveY - mPoint2ItemTop + mOffset2Top - mStatusHeight;
		mWindowManager.updateViewLayout(mDragImageView, mWindowLayoutParams); 
		onSwapItem(moveX, moveY);

		mHandler.post(mScrollRunnable);
	}


	private Runnable mScrollRunnable = new Runnable() {

		@Override
		public void run() {
			if(rawMoveX > mLeftScrollBorder){
				mHandler.postDelayed(mScrollRunnable, 200);
			}else if(rawMoveX < mRightScrollBorder){
				mHandler.postDelayed(mScrollRunnable, 200);
			}else{
				mHandler.removeCallbacks(mScrollRunnable);
			}
		}
	};

	private AnimatorSet createTranslationAnimations(View view, float startX,
			float endX, float startY, float endY) {
		ObjectAnimator animX = ObjectAnimator.ofFloat(view, "translationX",
				startX, endX);
		ObjectAnimator animY = ObjectAnimator.ofFloat(view, "translationY",
				startY, endY);
		AnimatorSet animSetXY = new AnimatorSet();
		animSetXY.playTogether(animX, animY);
		return animSetXY;
	}

	private void animateReorder(final int oldPosition, final int newPosition) {
		boolean isForward = newPosition > oldPosition;
		List<Animator> resultList = new LinkedList<Animator>();
		if (isForward) {
			for (int pos = oldPosition; pos < newPosition; pos++) {
				View view = getChildAt(pos - getFirstVisiblePosition());

				resultList.add(createTranslationAnimations(view,
						view.getWidth(), 0, 0, 0));
			}
		} else {
			for (int pos = oldPosition; pos > newPosition; pos--) {
				View view = getChildAt(pos - getFirstVisiblePosition());
				resultList.add(createTranslationAnimations(view,
						-view.getWidth(), 0, 0, 0));
			}
		}

		AnimatorSet resultSet = new AnimatorSet();
		resultSet.playTogether(resultList);
		resultSet.setDuration(300);
		resultSet.setInterpolator(new AccelerateDecelerateInterpolator());
		resultSet.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationStart(Animator animation) {
				mAnimationEnd = false;
			}

			@Override
			public void onAnimationEnd(Animator animation) {
				mAnimationEnd = true;
			}
		});
		resultSet.start();
	}

	private void onSwapItem(int moveX, int moveY){
		//获取我们手指移动到的那个item的position  
		int dstPosition = pointToPosition(moveX, moveY);  
		if (dstPosition ==0){
			dstPosition=1;
		}

		final int tempPosition = dstPosition;
		if(tempPosition != mDragPosition && tempPosition != AdapterView.INVALID_POSITION && mAnimationEnd){
			onReorderItemsListener.reorderItems(mDragPosition, tempPosition);
			mDragAdapter.setHideItem(tempPosition);
			
			final ViewTreeObserver observer = getViewTreeObserver();
			observer.addOnPreDrawListener(new OnPreDrawListener() {

				@Override
				public boolean onPreDraw() {
					observer.removeOnPreDrawListener(this);
					animateReorder(mDragPosition, tempPosition);
					mDragPosition = tempPosition;
					return true;
				}
			} );
		}
	}


	private void onStopDrag(){
		View view = getChildAt(mDragPosition - getFirstVisiblePosition());
		if(view != null){
			view.setVisibility(View.VISIBLE);
		}
		mDragAdapter.setHideItem(-1);

		removeDragImage();
	}

	private static int getStatusHeight(Context context){ //全屏可能还需要使用
		int statusHeight = 0;
		Rect localRect = new Rect();
		((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect);
		statusHeight = localRect.top;
		if (0 == statusHeight){
			Class<?> localClass;
			try {
				localClass = Class.forName("com.android.internal.R$dimen");
				Object localObject = localClass.newInstance();
				int i5 = Integer.parseInt(localClass.getField("status_bar_height").get(localObject).toString());
				statusHeight = context.getResources().getDimensionPixelSize(i5);
			} catch (Exception e) {
				e.printStackTrace();
			} 
		}
		return statusHeight;
	}


	public interface OnReorderItemsListener {
		public void reorderItems(int from, int to);
	}

}
